题解:P17511 [入门赛 #52] 月饼调配

612 字
3 分钟
题解:P17511 [入门赛 #52] 月饼调配

题目大意#

给定一个树状的仓库分布信息,每个仓库初始有一些月饼,要求月饼通过仓库之间的联络通道(容量有限)搬运至目标状态。求出通过通道搬运的最小次数。

思路讲解#

既然是树形的数据结构,遍历上就肯定要用深搜。我们看样例解释可以总结出一点小规律:

对于若干分别要放出月饼和收入月饼的仓库来说,优先匹配两个距离最近的点进行调配是最省次数的。(距离最近即从一个点到另一个点,所经过的边数最少。)

根据这个规律,可以确定一下大致思路:

  1. 树以任意点为根(后文为 11 号点),先搜索到每个叶子节点,计算出它们需要放出或收入多少月饼。
  2. 向它的父亲赠出或索要这些月饼(因为是树形数据结构,所以所有调配方案都要经过其父亲之手)。计算此处搬运所需次数。
  3. 父亲通过其他孩子赠出或索要到的月饼来调配,尽量满足刚才孩子仓库的需求。
  4. 若父亲也无法满足孩子的需要了,就向它的父亲继续赠出或索要。

由于保证月饼礼盒的当前总数与目标总数相同,所以此思路是完全可行的。

代码实现#

搜索部分

此处使用邻接表存图。代码中 cgcg 数组计算开始到结束仓库月饼的变化量。
搬运次数只与变化量绝对值和当前边单次可拿的最多数量有关,所以代码中用 abs 函数取了绝对值。当然不要忘了向上取整,若对代码中的取整方法有疑问也可以强转为小数类型,使用 ceil 函数向上取整(可能有精度问题)。

vector<pair<int,int> >a[200005];
void dfs(int x,int fa){
for(int i=0;i<a[x].size();i++){
int nxt=a[x][i].first,val=a[x][i].second;//这里一定要是局部变量,否则孩子的变量值会影响到父亲导致答案错误
if(nxt!=fa){
dfs(nxt,x);
cg[x]+=cg[nxt];//来自孩子的“赠予或索要”
cnt+=(abs(cg[nxt])+val-1)/val;//计算搬运次数
}
}
}
完整代码
#include<bits/stdc++.h>
using namespace std;
long long n,u,v,c,cnt;
int s[200005],t[200005],cg[200005];
vector<pair<int,int> >a[200005];
void dfs(int x,int fa){
for(int i=0;i<a[x].size();i++){
int nxt=a[x][i].first,val=a[x][i].second;
if(nxt!=fa){
dfs(nxt,x);
cg[x]+=cg[nxt];
cnt+=(abs(cg[nxt])+val-1)/val;
}
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>s[i];
}
for(int i=1;i<=n;i++){
cin>>t[i];
cg[i]=s[i]-t[i];
}
for(int i=1;i<=n-1;i++){
cin>>u>>v>>c;
a[u].push_back(make_pair(v,c));
a[v].push_back(make_pair(u,c));
}
dfs(1,0);
cout<<cnt;
return 0;
}

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

题解:P17511 [入门赛 #52] 月饼调配
https://zhedaotixuanbo.pages.dev/posts/题解:P17511 [入门赛 52] 月饼调配/
作者
zhedaotixuanbo
发布于
2026-09-27
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
zhedaotixuanbo
这道题选什么? _____!
公告
分类
标签
站点统计
文章
17
分类
1
标签
21
总字数
6,295
运行时长
0 天
最后活动
0 天前
站点信息
构建平台
Cloudflare Pages
博客版本
ZTXB v1.0.0
文章许可
CC BY-NC-SA 4.0